home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
dev
/
c
/
vbcc.lha
/
vbcc
/
pasm
/
output_ehf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-02-17
|
11KB
|
387 lines
/* $VER: pasm output_ehf.c V0.7 (02.01.98)
*
* This file is part of pasm, a portable PowerPC assembler.
* Copyright (c) 1997-98 Frank Wille
*
* pasm is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
* pasm may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v0.7 (02.01.98) phx
* Sections after a section with HUNK_EXT were 4 bytes too large.
* Output format OFMT_ADOS support. The difference between ADOS and
* and EHF is, that ADOS uses HUNK_CODE instead HUNK_PPC_CODE and
* doesn't support any PPC-specific relocations and references types.
* This makes it possible to link simple PowerPC programs with an
* old linker, like BLink, SLink or PhxLnk.
* v0.4 (02.07.97) phx
* File created.
*/
#define OUTPUT_EHF_C
#include "ppcasm.h"
#include "ehf.h"
struct XRefNode {
struct node n;
char *sym_name;
uint8 ref_type;
int noffsets;
struct list xreflist;
};
static char *output_name;
static int nsecs = 0;
static bool exthunk;
void output_ehf(struct GlobalVars *);
static void reloc_hunk(FILE *,struct Section *,uint8,uint32);
static void unsupp_relocs(struct Section *);
static void ext_header(FILE *);
static void ext_refs(FILE *,struct GlobalVars *,struct Section *);
static void ext_defs(FILE *,struct GlobalVars *,uint32,uint8,uint32);
static uint32 word_strlen(char *);
static void write_name(FILE *,struct GlobalVars *,char *);
static void fwalign(FILE *,struct GlobalVars *,uint32);
static void fw(FILE *,void *,size_t);
static void fw4(FILE *,uint32);
void output_ehf(struct GlobalVars *gv)
{
struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
struct Symbol *symchain;
uint32 index;
bool ehfmode = gv->output==OFMT_EHF;
FILE *fp;
/* assign an index to each valid section */
while (nextsec = (struct Section *)sec->n.next) {
if (!(sec->flags & SF_DISCARD) && sec->size > 0)
sec->index = nsecs++;
sec = nextsec;
}
/* create output file */
output_name = gv->dest_name;
if (fp = fopen(output_name,"w")) { /* create output file */
fw4(fp,HUNK_UNIT);
if (gv->ident) {
fw4(fp,word_strlen(gv->ident)); /* unit name */
write_name(fp,gv,gv->ident);
}
else
fw4(fp,0);
/* section loop */
sec = (struct Section *)gv->sectionlist.first;
while (nextsec = (struct Section *)sec->n.next) {
exthunk = FALSE;
if (!(sec->flags & SF_DISCARD) && sec->size > 0) {
index = sec->index;
/* section name */
fw4(fp,HUNK_NAME);
fw4(fp,word_strlen(sec->name));
write_name(fp,gv,sec->name);
/* section type and size */
switch(sec->type) {
case ST_CODE:
ehfmode ? fw4(fp,HUNK_PPC_CODE) : fw4(fp,HUNK_CODE);
break;
case ST_DATA:
fw4(fp,HUNK_DATA);
break;
case ST_UDATA:
fw4(fp,HUNK_BSS);
break;
default: /* section type not supported in EHF/ADOS */
error(52,sec->name,(int)sec->type);
fw4(fp,HUNK_DATA); /* defaults to HUNK_DATA */
break;
}
fw4(fp,(uint32)(sec->size+3)>>2);
/* write section contents */
if (!(sec->flags & SF_UNINITIALIZED)) {
fw(fp,sec->contents,(uint32)sec->size);
fwalign(fp,gv,(uint32)sec->size);
}
/* relocation hunks */
reloc_hunk(fp,sec,R_PPC_ADDR32,HUNK_ABSRELOC32);
/* @@@ reloc_hunk(fp,sec,R_PPC_ADDR16,HUNK_ABSRELOC16); */
if (ehfmode)
reloc_hunk(fp,sec,R_PPC_REL24,HUNK_RELRELOC26);
reloc_hunk(fp,sec,R_PPC_REL14,HUNK_RELRELOC16);
reloc_hunk(fp,sec,R_PPC_REL14_BRTAKEN,HUNK_RELRELOC16);
reloc_hunk(fp,sec,R_PPC_REL14_BRNTAKEN,HUNK_RELRELOC16);
reloc_hunk(fp,sec,R_PPC_REL32,HUNK_RELRELOC32);
reloc_hunk(fp,sec,R_PPC_TOC16,HUNK_DREL16);
unsupp_relocs(sec); /* print unsupported relocations */
/* external references and global definitions */
ext_refs(fp,gv,sec);
ext_defs(fp,gv,index,SYM_RELOC,EXT_DEF);
if (index == 0) /* put absolute definitions in first HUNK_EXT */
ext_defs(fp,gv,0xffff,SYM_ABS,EXT_ABS);
if (exthunk)
fw4(fp,0); /* close HUNK_EXT block */
/* symbol table */
ext_defs(fp,gv,index,SYM_RELOC,EXT_SYMB);
fw4(fp,HUNK_END); /* end of this hunk */
}
sec = nextsec;
}
fclose(fp);
}
else
error(25,output_name); /* unable to create output file */
}
static void reloc_hunk(FILE *fp,struct Section *sec,uint8 r,uint32 ehfrel)
/* generate an EHF relocation hunk for a specific reloc type */
{
struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
struct list **rlist=alloc(nsecs*sizeof(struct list *));
int *rcnt=alloczero(nsecs*sizeof(int)); /* reloc cnt for all sections */
bool hunk_required=FALSE;
int i;
for (i=0; i<nsecs; i++) { /* empty reloc lists for each section */
rlist[i] = alloc(sizeof(struct list));
initlist(rlist[i]);
}
while (nextrel = (struct Reloc *)rel->n.next) {
if (rel->type == r) {
/* move reloc node of correct type into relocssect's rlist */
remnode(&rel->n);
addtail(rlist[rel->relocsect->index],&rel->n);
rcnt[rel->relocsect->index]++;
hunk_required = TRUE;
}
rel = nextrel;
}
if (hunk_required) { /* there's at least one relocation */
fw4(fp,ehfrel); /* reloc hunk id */
for (i=0; i<nsecs; i++) {
if (rcnt[i]) {
fw4(fp,(uint32)rcnt[i]); /* number of relocations */
fw4(fp,(uint32)i); /* section index */
/* store relocation offsets */
while(rel = (struct Reloc *)remhead(rlist[i])) {
fw4(fp,(uint32)rel->offset);
free(rel);
}
}
}
fw4(fp,0); /* no more relocation entries */
}
/* free dynamically allocated rlists and rcnt array */
for (i=0; i<nsecs; free(rlist[i++]));
free(rcnt);
}
static void unsupp_relocs(struct Section *sec)
{
struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
while (nextrel = (struct Reloc *)rel->n.next) {
error(53,elfrel_name[rel->type & ELFRELNAMMSK],rel->offset,sec->name);
rel = nextrel;
}
}
static void ext_header(FILE *fp)
{
if (!exthunk) {
exthunk = TRUE;
fw4(fp,HUNK_EXT);
}
}
static void ext_refs(FILE *fp,struct GlobalVars *gv,struct Section *sec)
{
struct list xnodelist; /* xrefs with same ref. type and symbol name */
struct XRefNode *xn,*nextxn;
struct XReference *xref;
initlist(&xnodelist);
while (xref = (struct XReference *)remhead(&sec->xreflist)) {
char *name = xref->xsymbol->name; /* name of xref'ed symbol */
uint8 rtype = xref->type;
/* ELF32 -> EHF reference type mapping */
switch (rtype) {
case R_PPC_ADDR32:
rtype = EXT_ABSREF32;
break;
case R_PPC_REL14:
case R_PPC_REL14_BRTAKEN:
case R_PPC_REL14_BRNTAKEN:
case R_PPC_ADDR16:
rtype = EXT_RELREF16;
break;
case R_PPC_TOC16:
rtype = EXT_DEXT16; /* small data */
break;
case R_PPC_REL24:
if (gv->output == OFMT_EHF) {
rtype = EXT_RELREF26;
break;
}
default:
error(53,elfrel_name[rtype & ELFRELNAMMSK],xref->offset,sec->name);
rtype = EXT_RELREF8; /* @@@ to keep the loop running */
break;
}
/* search appropriate XRefNode for referenced symbol and type */
xn = (struct XRefNode *)xnodelist.first;
while (nextxn = (struct XRefNode *)xn->n.next) {
if (!strcmp(name,xn->sym_name) && rtype==xn->ref_type)
break;
xn = nextxn;
}
if (nextxn==NULL) { /* we have to create a new XRefNode? */
xn = alloc(sizeof(struct XRefNode));
xn->sym_name = name;
xn->ref_type = rtype;
xn->no